Cannot implicitly convert type 'Int' to 'T'
Any time you find yourself switching on a type in a generic you are almost certainly doing something wrong. Generics should be generic; they should operate identically completely independent of the type.
If T can only be int or string then don't write your code this way at all in the first place. Write two methods, one that returns an int and one that returns a string.
Cannot convert value of type 'Int' to expected argument type 'Int' in generic
func notify<Int>(data: Int, value: Int, at indexPath: IndexPath?) {
buttonSelection.updateTag(tag:value, for:indexPath)
}
This is not how you implement a method that takes Int
. That <Int>
means you have a generic method with a parameter called Int
. It's not the integer type Int
but name of the generic parameter, same as <T>
:
If you declare a generic method in a protocol you cannot implement just one type, you have to implement all the types.
It's possible you actually want to use a protocol with an associated type and not generics:
protocol NotifyDataSelected: class {
associatedtype T
func notify(data: T, value:T, at indexPath: IndexPath?)
}
extension MainButtons: NotifyDataSelected {
typealias T = Int
func notify(data: Int, value: Int, at indexPath: IndexPath?) {
}
}
Java Generics cannot convert Type in Type
Why is the first one working and the second one isn't?
Because List<ASpecificSubTypeOfTestType>
(the return of the first method) is a subtype of List<? extends TestType>
, but Pair<String, List<ASpecificSubTypeOfTestType>>
(the return of the second method) is not a subtype of Pair<String, List<? extends TestType>>
.
Let us change your example from Pair
to List
, and TestType
to Object
for a moment:
public class Test {
public static void main( String [] args ) throws Exception {
Collection<?> val = null;
List<?> single = testSingle( val ); // OK
List<List<?>> pair = testList( val ); // ERROR
}
static <T> List<T> testSingle( Collection<T> val ){
return null;
}
static <T> List<List<T>> testList( Collection<T> val ){
return null;
}
}
From a technical point of view, List<SomeSpecificType>
is a subtype of List<?>
, but List<List<SomeSpecificType>>
is not a subtype of List<List<?>>
, for the same reason that List<String>
is not a subtype of List<Object>
-- the type parameters are different concrete types (one is List<SomeSpecificType>
and the other is List<?>
).
For a more practical reasoning, testList
returns a List<List<T>>
for some T
. We don't know what that T
is, but we know that it is some concrete type. And this List<List<T>>
that is returned is a list that can only contain List<T>
. It cannot contain List<S>
if S is not T, because List<S>
and List<T>
are not subtypes of each other. Even though we don't know what T is, we know that there exists some choice of T, and all the element lists must have that T as the type parameter.
On the other hand, the type you're assigning it to, List<List<?>>
, is a list that can contain every type of list at the same time. So you can put in a List<Integer>
and a List<String>
, etc. at the same time and it would be okay. You can never do that with a List<List<T>>
, no matter what you choose T
to be.
Therefore, the two types are clearly incompatible.
What can go wrong? With the List<List<?>>
reference, you can insert List<Integer>
and List<String>
into the list. And then with the List<List<T>>
reference inside the function, you can extract all the elements as List<T>
, which they won't be. So it is unsafe.
You might say, what if I never put things into the List<List<?>>
reference? Is that safe? But if that were the case, you should instead use List<? extends List<?>>
. The ? extends
wildcard makes it a consumer, so you cannot insert anything into it except null
; and it also makes the type compatible (List<List<SomeSpecificType>>
is a subtype of List<? extends List<?>>
).
The moral of the story is, wildcards in deeper parameters do not mean what you think they do.
Unable to assign untyped int to generic struct field
Instantiation must happen at the type level, not on a method level, and methods can't introduce new type parameters, see How to create generic method in Go? (method must have no type parameters)
This means when you want to use R2
, you then have to choose type arguments for the type parameters, and the methods can't change those, you're "stuck" with the types you choose on R2
's instantiation.
Also note that since the constraint for IDTYPE
is comparable
, which may be string
for example, the integer 123
cannot be assigned to the ID
field in all cases because it may have a type of string
.
If you want / must handle multiple concrete types for the IDs, generics is not the right choice. Interfaces may be used instead:
type R2 struct {
ID any
IsActive bool
}
Also note that the receiver must be a pointer if you wish to modify the receiver (e.g. fields of a struct).
If you wish to restrict the values stored in ID
to comparable
, use a (generic) function for it.
Here's how you can do it:
type R2 struct {
ID any
IsActive bool
}
func (r *R2) Store(ctx context.Context) error {
setID(r, 123)
return nil
}
func setID[ID comparable](r *R2, id ID) {
r.ID = id
}
Testing it:
r := &R2{}
var s Storable = r
s.Store(context.TODO())
fmt.Println(r)
Which outputs (try it on the Go Playground):
&{123 false}
This provides flexibility (you can set any comparable values to the ID
field using setID()
), and provides compile-time safety: attempting to set an incomparable value will result in a compile-time error such as this:
setID(r, []int{1}) // Error: []int does not implement comparable
Value of type 'T' cannot be converted to
Even though it's inside of an if
block, the compiler doesn't know that T
is string
.
Therefore, it doesn't let you cast. (For the same reason that you cannot cast DateTime
to string
)
You need to cast to object
, (which any T
can cast to), and from there to string
(since object
can be cast to string
).
For example:
T newT1 = (T)(object)"some text";
string newT2 = (string)(object)t;
Why can't I cast an item to a generic type — where the generic type is an interface, and after checking that the item implements said interface?
Here you go:
if (effect is T typed) {
effects.Add(typed);
}
As for why: you'd need an object
cast in the middle: (T)(object)effect
Related Topics
"'Init' Is Deprecated" Warning After Swift4 Convert
Swift: How to Add a Class Method in 'string" Extension
Variable with Getter/Setter Cannot Have Initial Value, on Overridden Stored Property
Nstoolbarflexiblespaceitem Is Constraint to Nssplitviewitem in Swift
Conversion Between Cgfloat and Nsnumber Without Unnecessary Promotion to Double
Member Operator '==' Must Have at Least One Argument of Type
Sizing a UIpickerview Inside a UIalertview
Convert/Wrap Swift Struct as Nsvalue for Caanimation Purposes
Why Do I Get Source Kit Service Terminated Error
Uitextview Contentoffset Is Set
How to a Convert a Dictionary Slice to a Dictionary in Swift
Swift Playground with Debugger Support
How to Observe Object's Property in Rxswift
Can You Strict Generic Types or Give One Parameter More Than One Type